var logger = require('./logger');

class Lock {

    constructor(redisClient, key, lockTime) {
        this.redisClient = redisClient; // redis client实例
        this.key = key; // redis锁名称key, 唯一性考虑
        this.lockTime = lockTime; // 锁对应的时间值
    }

    unlock() {
        this.redisClient.get(this.key, (err, res) => {
            if (err) {
                logger.error(`[Lock] ${err}`);
            } else {
                if (res == this.lockTime) {
                    this.redisClient.del(this.key, (err, res) => {
                        if (err) {
                            logger.error(`[Lock] ${err}`);
                        } else {
                            logger.debug(`[Lock] unlock >> ${res === 1}`);
                        }
                    });
                } else {
                    logger.debug('[Lock] lock time is not matched!');
                }
            }
        })
    }
}


// redis lock操作
class RedisLock {

    constructor(redisClient, key = `lock-key`, expireTime = 60 * 1000) {
        this.redisClient = redisClient; // redis client实例
        this.key = `${key}-` + Date.now; // redis锁名称key, 唯一性考虑
        this.expireT = expireTime; // redis锁过期时间 TODO 需要调优
    }

    // 获取redis lock，返回promise
    lock() {
        return new Promise((resolve, reject) => {
            let t = Date.now() + this.expireT + 1;
            this.redisClient.setnx(this.key, t, (err, res) => {
                if (err) {
                    logger.error(`[RedisLock] ${err}`);
                    reject(err);
                } else {
                    if (res === 1) {
                        // got lock
                        logger.debug("[RedisLock] got lock.");
                        resolve(new Lock(this.redisClient, this.key, t));
                    } else {
                        this.redisClient.get(this.key, (err, res) => {
                            if (err) {
                                logger.error(`[RedisLock] ${err}`);
                                reject(err);
                            } else {
                                if (res && +res < Date.now()) {
                                    this.redisClient.getset(this.key, t, (err, res2) => {
                                        if (err) {
                                            logger.error(`[RedisLock] ${err}`);
                                            reject(err);
                                        } else {
                                            if (res2 === res) {
                                                // got lock
                                                logger.debug("[RedisLock] expired got lock.");
                                                resolve(new Lock(this.redisClient, this.key, t));
                                            } else {
                                                resolve(false);
                                            }
                                        }
                                    });
                                } else {
                                    resolve(false);
                                }
                            }
                        })
                    }
                }
            })
        });
    }
}

exports.RedisLock = RedisLock;